﻿Imports System.Collections.ObjectModel
Imports System.Data
Imports System.IO
Imports System.IO.Ports
Imports System.Text
Imports System.Threading
Imports System.Windows.Threading
Imports FL_8x0.Common
Imports FL_8x0.FL_800.Model
Imports FL_8x0.Model
Imports FL_8x0.View
Imports GalaSoft.MvvmLight
Imports GalaSoft.MvvmLight.CommandWpf
Imports GalaSoft.MvvmLight.Messaging
Imports GalaSoft.MvvmLight.Threading
Imports Microsoft.Win32
Imports OxyPlot


Namespace FL_8x0.FL_800.ViewModel
    Public Class LeakTestViewModel
        Inherits ViewModelBase


        Private _gp1 As String            '直压1
        Private _gp2 As String            '直压2
        Private _dp As String             '差压
        Private _temp As String           '温度


        Private ReadOnly _unActiveColor As Brush = New SolidColorBrush(Color.FromRgb(230, 230, 230))  '不活动时颜色
        Private ReadOnly _activeColor As Brush = New SolidColorBrush(Color.FromRgb(38, 73, 154))      '活动时颜色

        Private ReadOnly _whiteColor As Brush = New SolidColorBrush(Colors.White)      '白色
        Private ReadOnly _blackColor As Brush = New SolidColorBrush(Colors.Black)      '黑色

        Private _startMode As String = "S"             '启动模式
        Private _startModeCommand As RelayCommand(Of String)    '点击“启动模式”触发命令（事件）
        Private _startCommand As RelayCommand             '点击“启动” 触发命令（事件）
        Private _stopCommand As RelayCommand              '点击“停止” 触发命令（事件）

        Private _productSelectCmd As RelayCommand


        Private _enableButton As Boolean                  '新建报告、停止 按钮状态
        Private _enableStart As Boolean

        Private _readyCounter As UShort = 0

        Private _isReadOther As Boolean = False
        Private _isM4 As Boolean = False




        Private ReadOnly _normalColor As Brush = New SolidColorBrush(ColorConverter.ConvertFromString("#808080")) '不可用颜色
        Private ReadOnly _ngColor As Brush = New SolidColorBrush(ColorConverter.ConvertFromString("#EB3636"))     'NG色
        Private ReadOnly _okColor As Brush = New SolidColorBrush(ColorConverter.ConvertFromString("#99FF00"))     'OK色

        Private ReadOnly _nsMain As New NumberStates  '1级 状态机（控制主时序）
        '                                   （-1=ready，0=延时,1=充气，2=平衡，3=检漏，4=排气）

        Private _info As MiddleInfoModel
        Private _operationText As String                  '操作按钮显示文字  连接/断开

        Private _saveWaveCmd As RelayCommand
        Private _ngResult As String

        Private _minY1 As Double
        Private _maxY1 As Double
        Private _minY2 As Double
        Private _maxY2 As Double
        Private _yLabel As String
        Private _gpPoints As ObservableCollection(Of DataPoint) '直压曲线
        Private _dpPoints As ObservableCollection(Of DataPoint) '差压曲线

        Private ReadOnly _waveX = New List(Of String)       'X轴点数据
        Private ReadOnly _waveY0 = New List(Of String)      '直压点数据
        Private ReadOnly _waveY1 = New List(Of String)      '差压点数据

        Private _machineSelectCmd As RelayCommand
        Private _opearteCmd As RelayCommand
        Private _startModeCmd As RelayCommand
        Private _resetCmd As RelayCommand

        Private _resultTable As DataTable

        Private _curRow As DataRow

        Private _prePress = 0
        Private _lngPress = 1

        Private _sngAxisInterval = 5

        Private _lngTimeTick As Integer = 0           '时间戳
        Private _lngAutoStartTime As Integer = 0     '自动启动定时

        Private _infoHeigh As GridLength

        Private _isFullTable As Boolean = False

        Private _repeat As Boolean        '重复检测
        Private _repeatNum As UShort      '重复次数
        Private _repeatInterval As UShort

        Private _productName As String
        Private _productCode As String
        Private _productCodeBuffer As String
        Private _isStart As Boolean
        Private _timer As DispatcherTimer

        Private _linkTickStart = 0

        Private _gPTracker As String
        Private _dPTracker As String

        Private _exportCmd As RelayCommand
        Private _readHistoryCmd As RelayCommand

        Private _clearCmd As RelayCommand

        Public Sub New()
            _machineSelectCmd = New RelayCommand(Sub() Call New ConnectInfo().ShowDialog())
            _opearteCmd = New RelayCommand(AddressOf Operate)

            StartModeCmd = New RelayCommand(Of String)(Sub(mode As String) _startMode = mode)
            StartCmd = New RelayCommand(AddressOf Start)
            StopCmd = New RelayCommand(Sub()
                                           Dim result = g_udtFL800Sync.WriteResetSync(Chr(SerialPortServer.ENQ) & "R")
                                           Repeat = False
                                           _isStart = False
                                           If _isFullTable Then
                                               Table_DelBlankLine()
                                           End If
                                       End Sub)
            SaveWaveCmd = New RelayCommand(AddressOf SaveWave)
            ExportCmd = New RelayCommand(AddressOf SaveResult)
            ReadHistoryCmd = New RelayCommand(AddressOf ReadHistory)
            ClearCmd = New RelayCommand(AddressOf Clear)

            InitColorStatus()
            OperationText = "连接"
            _nsMain.Init(-1, 4)
            NgResult = "NG"

            GpPoints = New ObservableCollection(Of DataPoint)()
            DpPoints = New ObservableCollection(Of DataPoint)()

            InfoHeigh = New GridLength(5, GridUnitType.Star)

            FlashTable("")

            Messenger.Default.Register(Of String)(Me, "Mode-Select", AddressOf FlashTable)

            Messenger.Default.Register(Of Message)(Me, "DataReceived", AddressOf DataReceive)

            Messenger.Default.Register(Of Message)(Me, "Group", AddressOf AddGroup)


            _productSelectCmd = New RelayCommand(
                Sub()
                    If User_ListProduct.Count <= 0 Then
                        log.WriteLogError("查询产品", "当前产品库为空，请先添加产品")
                    Else
                        Dim tp As Type = Type.[GetType](String.Format("FL_8x0.{0}.View.CreateReportWindow", Machine))
                        Dim dialog = CType(Activator.CreateInstance(tp), Window)
                        dialog.ShowDialog()
                        If dialog.DialogResult Then
                            'WriteProduct()
                            'Dim count = 0
                            'While (Not SystemData.udtFl800.IsWritten)
                            '    If count = 100 Then
                            '        Exit While
                            '    End If
                            '    count = count + 1
                            '    Thread.Sleep(50)
                            'End While
                            'If count = 100 Then
                            '    MessageBox.Show("数据写入失败")
                            '    Exit Sub
                            'End If

                            Dim result = WriteProduct()
                            If Not result Then
                                g_udtReport.ReportId = ""
                                MessageBox.Show("数据写入失败")
                                Exit Sub
                            End If


                            EnableStart = True
                            _isFullTable = True
                            FlashTable("")
                            ProductName = g_udt800.Name
                        End If
                    End If
                End Sub)

            _timer = New DispatcherTimer With {
                .Interval = TimeSpan.FromMilliseconds(100),
                .IsEnabled = g_udtFL800Sync.IsRunning
            }
            GPTracker = "直压" & vbLf & "测试压(kPa)：{4:0.00}" & vbLf & "时间(s)：{2:0.##}"
            DPTracker = "差压" & vbLf & "差压(Pa)：{4:0.0}" & vbLf & "时间(s)：{2:0.##}"

            AddHandler _timer.Tick, AddressOf FlashView
            Messenger.Default.Register(Of String)(Me, "update_product",
                                              Sub()
                                                  ProductName = g_udt800.Name
                                                  g_udtReport.ReportId = SystemData.idWorker.nextId()
                                                  g_udtReport.ProductId = g_udt800.Id
                                                  g_udtReport.ProductCode = IIf(ProductCode <> "", ProductCode, "空")
                                                  User_AddReport(g_udtReport)
                                              End Sub)
        End Sub

        Private Sub AddGroup(m As Message)
            Dim group = TryCast(m.Msg, GroupModel)
            If group IsNot Nothing Then
                If SystemData.Version = Version_800_113 Then
                    group.Times(8) = 0.0
                    group.MiddleJudgment = False
                    group.TestPDAC = 0
                    group.LeadPDAC = 0
                End If

                group.Id = SystemData.idWorker.nextId()
                group.Name = "启动自动添加" & Date.Now.ToString("yyyyMMddHHmmss")
                group.Model = "空"
                group.Temporary = True
                Dim sb5, sb6, sb7, sb8 As New StringBuilder
                For i = 7 To 0 Step -1
                    sb5.Append(IIf(group.Sv5List(i), "1", "0"))
                    sb6.Append(IIf(group.Sv6List(i), "1", "0"))
                    sb7.Append(IIf(group.Sv7List(i), "1", "0"))
                    sb8.Append(IIf(group.Sv8List(i), "1", "0"))
                Next
                group.SV5Mode = sb5.ToString
                group.Sv6Mode = sb6.ToString
                group.SV7Mode = sb7.ToString
                group.SV8Mode = sb8.ToString

                group.IsMs = Machine = Model_800MS
                Dim result As Boolean = group.WriteProduct(Database.g_dbConn测试记录, "首次启动读取", False)

                If result Then
                    g_udtReport.ReportId = SystemData.idWorker.nextId()
                    g_udtReport.ProductId = group.Id
                    g_udtReport.ProductCode = "空"
                    User_AddReport(g_udtReport)
                    g_udt800 = group
                    EnableStart = True
                    '_isFullTable = True
                    FlashTable("")
                    ProductName = g_udt800.Name
                End If


            End If
            IsReadOther = False
        End Sub

        Private Sub Clear()
            If ResultTable.Rows.Count > 0 Then
                If MsgBox("是否导出现有记录？", vbYesNo, "保存") = vbYes Then
                    SaveResult() '保存全部记录
                End If
            End If
            IsReadOther = True
            Dim result = g_udtFL800Sync.WriteOperateSync(ChrW(SerialPortServer.ENQ) & "7")
            If Not result Then
                log.WriteLogWarn("清空记录", "清空仪器记录失败")
            End If
            IsReadOther = False
            ResultTable.Clear()
        End Sub

        Private Sub ReadHistory()
            If ResultTable.Rows.Count > 0 Then
                If MsgBox("读取设备历史记录会覆盖现有记录，是否导出现有记录？", vbYesNo, "保存") = vbYes Then
                    SaveResult() '保存全部记录
                End If
            End If
            _isFullTable = False
            IsReadOther = True
            g_udtFL800Sync.Write(Chr(5) & "6" & Chr(6), ReadResultCmd)
            FlashTable("")
        End Sub

        Private Sub FlashView(sender As Object, e As EventArgs)
            FlashProcess(_lngPress)
            RepeatDetection()
            ScanRun()
        End Sub

        Private Sub Start()
            IsReadOther = True
            If g_udtReport.ReportId Is Nothing Or g_udtReport.ReportId = "" Then
                log.WriteLogError("启动", "请先[选择产品]！")
                If Repeat Then
                    Repeat = False
                End If
                Exit Sub
            End If

            Dim result = g_udtFL800Sync.WriteResetSync(Chr(SerialPortServer.ENQ) & "R")
            If _isFullTable Then
                Table_DelBlankLine()
            End If
            If Not result Then
                log.WriteLogError("停止检测", "停止检测失败")
                Exit Sub
            End If

            If (Not String.IsNullOrEmpty(ProductCode) AndAlso SystemData.Version = Version_800_127 AndAlso
                g_udtOtherSet.blnWriteToMachine) Then
                result = g_udtFL800Sync.WriteSNSync(Chr(SerialPortServer.ENQ) & ")", ProductCode)
                If Not result Then
                    log.WriteLogError("写入SN", "写入SN失败")
                    Exit Sub
                End If
            End If

            result = g_udtFL800Sync.WriteOperateSync(Chr(SerialPortServer.ENQ) & _startMode)
            If _isFullTable AndAlso result Then
                Table_AddNewLine()
                _isStart = True
            ElseIf Not result Then
                log.WriteLogError("启动检测", "启动检测失败")
            End If

            IsReadOther = False

        End Sub

        Private Sub FlashTable(obj As String)
            Dim table = New DataTable
            If SystemData.strLink = "" Then
                If _isFullTable Then
                    For i = 0 To g_strResult_800.Length - 1
                        table.Columns.Add(New DataColumn(g_strResult_800(i)))
                    Next
                Else
                    For i = 0 To g_strCol_800.Length - 1
                        table.Columns.Add(New DataColumn(g_strCol_800(i)))
                    Next
                End If
            Else
                Dim links = SystemData.strLink.Split(",")
                If SystemData.Machine = Model_800 Then
                    If Not links(4) = "800-M4" Then
                        InfoHeigh = New GridLength(0)
                        _isM4 = False
                    Else
                        InfoHeigh = New GridLength(3, GridUnitType.Star)
                        _isM4 = True
                    End If
                    If _isFullTable Then
                        For i = 0 To g_strResult_800.Length - 1
                            table.Columns.Add(New DataColumn(g_strResult_800(i)))
                        Next
                    Else
                        For i = 0 To g_strCol_800.Length - 1
                            table.Columns.Add(New DataColumn(g_strCol_800(i)))
                        Next
                    End If
                    ResultTable = table
                ElseIf SystemData.Machine = Model_800MS Then
                    If Not links(4) = "800MS-M2" Then
                        InfoHeigh = New GridLength(0)
                        _isM4 = False
                    Else
                        InfoHeigh = New GridLength(3, GridUnitType.Star)
                        _isM4 = True
                    End If

                    If _isFullTable Then
                        For i = 0 To g_strResult_800MS.Length - 1
                            table.Columns.Add(New DataColumn(g_strResult_800MS(i)))
                        Next
                    Else
                        For i = 0 To g_strCol_800MS.Length - 1
                            table.Columns.Add(New DataColumn(g_strCol_800MS(i)))
                        Next
                    End If
                    ResultTable = table
                End If
            End If

        End Sub

        Private Sub DataReceive(m As Message)
            Select Case m.Type
                Case "Pressure"
                    Dim msg = TryCast(m.Msg, MiddleInfoModel)
                    If msg IsNot Nothing Then
                        DispatcherHelper.CheckBeginInvokeOnUI(
                            Sub()
                                Info = msg
                                Gp1 = msg.Gp1 & " kPa"

                            End Sub)
                        'SystemData.udtFl800.StrOperationCmd = ReadPressureCmd
                        'SystemData.udtFl800.Write(Chr(SerialPortServer.ENQ) & "5" & Chr(SerialPortServer.ACK)) '读当前压力
                    End If
                Case "Middle-Info"
                    Dim msg = TryCast(m.Msg, MiddleInfoModel)
                    If msg IsNot Nothing Then
                        DispatcherHelper.CheckBeginInvokeOnUI(
                            Sub()
                                Info = msg
                                If Not String.IsNullOrEmpty(msg.Gp2) Then
                                    Gp2 = msg.Gp2 & " kPa"
                                End If
                                If Not String.IsNullOrEmpty(msg.Dp) Then
                                    Dp = msg.Dp & " Pa"
                                End If
                                If Not String.IsNullOrEmpty(msg.Temp) Then
                                    Temp = msg.Temp & " ℃"
                                End If
                                ChartAddPoint()
                            End Sub)
                    End If
                Case "Process"
                    If m.Msg IsNot Nothing Then
                        Dim curPress = UShort.Parse(m.Msg)
                        DispatcherHelper.CheckBeginInvokeOnUI(
                            Sub()
                                If curPress = 1 Then
                                    _prePress = 0
                                End If
                                _prePress = _lngPress
                                _lngPress = curPress

                                If _prePress = 1 Or (_lngPress > 1 And _prePress = 0) Then
                                    ChartInit()
                                    NgResult = "NG"
                                    ResultBackColorList(0) = _unActiveColor
                                    ResultBackColorList(1) = _unActiveColor
                                End If
                                _linkTickStart = My.Computer.Clock.TickCount
                                'Call FlashProcess(curPress)
                            End Sub)
                    End If
                Case "Result"
                    Dim msg = TryCast(m.Msg, ResultModel)
                    If msg IsNot Nothing Then
                        DispatcherHelper.CheckBeginInvokeOnUI(
                    Sub()
                        If _isFullTable Then
                            If _curRow Is Nothing Then
                                If g_udtReport.ReportId IsNot Nothing Then
                                    Table_AddNewLine()
                                Else
                                    _curRow = ResultTable.NewRow
                                End If
                            End If
                            If Machine = Model_800 Then
                                _curRow(6) = Date.Now
                                _curRow(7) = msg.Sdet
                                _curRow(11) = msg.Judgment
                            Else

                            End If
                            User_AddRecord800(_curRow, _isFullTable)
                            _curRow = Nothing
                        Else

                            Dim row = ResultTable.NewRow
                            row(0) = msg.No
                            row(1) = msg.Group
                            row(2) = msg.DateTime
                            row(3) = IIf(ProductCode <> "", ProductCode, "空")

                            If SystemData.Machine = Model_800 Then
                                For i = 4 To 10
                                    row(i) = msg.Timers(i - 4)
                                Next
                                row(11) = msg.Sdet

                            ElseIf SystemData.Machine = Model_800MS Then
                                For i = 4 To 9
                                    row(i) = msg.Timers(i - 4)
                                Next
                                row(10) = msg.Sdet
                                row(11) = msg.Ldet
                            End If
                            row(12) = msg.Unit
                            row(13) = msg.Judgment
                            ResultTable.Rows.Add(row)

                            If SystemData.Machine = Model_800 Then
                                User_AddRecord800(row, False)
                            Else
                                User_AddRecord800MS(row, False)
                            End If

                        End If

                        If msg IsNot Nothing Then
                            If Not msg.Judgment.Contains("OK") Then
                                NgResult = msg.Judgment
                                ResultBackColorList(0) = _unActiveColor
                                ResultBackColorList(1) = _ngColor
                            Else
                                NgResult = "NG"
                                ResultBackColorList(0) = _okColor
                                ResultBackColorList(1) = _unActiveColor
                            End If
                        End If

                        _isStart = False

                    End Sub)
                    End If
            End Select
        End Sub

        Private Sub Operate()
            If OperationText = "连接" Then
                ' Dim result = SystemData.udtFl800.StartServer(SystemData.strLink)
                Dim result = SystemData.g_udtFL800Sync.StartServer(SystemData.strLink)
                If result Then
                    EnableButton = True
                    OperationText = "断开"
                    _timer.IsEnabled = True
                    'SystemData.udtFl800.StrOperateCommand = ReadPressureCmd
                    'SystemData.udtFl800.Write(Chr(SerialPortServer.ENQ) & "5" & Chr(SerialPortServer.ACK)) '读当前压力
                    IsReadOther = True
                    If SystemData.Machine = Model_800 And SystemData.Version <> Version_800_113 Then
                        SystemData.g_udtFL800Sync.ReadGroupSync(Chr(SerialPortServer.ENQ) & "8" & Chr(SerialPortServer.ACK))
                    Else
                        SystemData.g_udtFL800Sync.ReadGroupSync(Chr(SerialPortServer.ENQ) & "1" & Chr(SerialPortServer.ACK))
                    End If
                End If
            ElseIf OperationText = "断开" Then
                ' Dim result = SystemData.udtFl800.StopServer()
                Dim result = SystemData.g_udtFL800Sync.StopServer()
                If result Then
                    _timer.IsEnabled = False
                    ProductName = ""
                    g_udtReport.ReportId = Nothing
                    EnableButton = False
                    EnableStart = False
                    OperationText = "连接"
                End If
            End If
        End Sub


        '=====================================================================
        '函 数 名: SaveWave
        '参    数: 
        '返 回 值:
        '功能描述: （保存曲线）
        '=====================================================================
        Private Sub SaveWave()
            If ResultTable.Rows.Count > 0 Then  '有测试记录
                '用户保存
                Dim saveDialog As New SaveFileDialog With {
                        .Filter = "CSV文件|*.csv|所有文件|*.*",
                        .FileName = ""
                        }
                saveDialog.ShowDialog()

                If saveDialog.FileName <> "" Then
                    SaveWaveCsv(saveDialog.FileName)  '保存曲线记录
                End If
            Else
                log.WriteLogError("保存曲线", "曲线无数据，无法导出")
            End If
        End Sub

        '======================================================================================
        '函 数 名: SaveWaveCsv
        '参    数: 
        '返 回 值: 
        '功能描述: 保存曲线到CSV文本文件
        '======================================================================================
        Private Sub SaveWaveCsv(strFileName As String)
            If _waveX.Count > 0 Then  '有测试记录
                If Directory.Exists(g_udtOtherSet.strAutoSaveWavePath) = False Then '文件夹不存在
                    Directory.CreateDirectory(g_udtOtherSet.strAutoSaveWavePath)
                End If

                Dim swFile As StreamWriter = New StreamWriter(strFileName, False, Encoding.Default)

                swFile.Write("时间(s),测试压(kPa),差压(Pa)" & vbCrLf)

                Dim i As UInt16

                Dim strRow As String

                Try
                    For i = 0 To _waveX.Count - 1
                        strRow = CStr(_waveX(i)) & ", "
                        strRow &= CStr(_waveY0(i)) & ", "
                        strRow &= CStr(_waveY1(i))

                        swFile.Write(strRow & vbCrLf)
                    Next
                Catch ex As Exception
                    log.WriteLogError("SaveWaveCsv():" & strFileName, ex.Message)
                End Try

                swFile.Close()
            End If
        End Sub


        '=====================================================================
        '函 数 名: SaveResult
        '参    数: 
        '返 回 值:
        '功能描述: 弹出文件选择框，保存测试结果CSV
        '=====================================================================
        Public Sub SaveResult()
            If ResultTable.Rows.Count > 0 Then  '有测试记录
                '用户保存
                Dim saveDialog As New SaveFileDialog With {
                        .Filter = "CSV文件|*.csv|所有文件|*.*",
                        .FileName = ""
                        }
                saveDialog.ShowDialog()

                If saveDialog.FileName <> "" Then
                    SaveResultCsv(saveDialog.FileName)  '保存全部记录
                End If
            Else
                log.WriteLogError("导出记录", "当前无记录数据，无法导出")
            End If
        End Sub

        '=====================================================================
        '函 数 名: SaveResultCsv
        '参    数: strFileName csv文件名
        '返 回 值:
        '功能描述: 将测试结果写入CSV文件
        '=====================================================================
        Private Sub SaveResultCsv(strFileName As String)
            If ResultTable.Rows.Count > 0 Then  '有测试记录
                Dim swFile = New StreamWriter(strFileName, False, Encoding.Default)

                Dim r As Integer
                Dim c As Integer

                Dim strRow As String

                Try
                    strRow = ""
                    For c = 0 To ResultTable.Columns.Count - 1
                        strRow &= ResultTable.Columns(c).ColumnName & ","
                    Next
                    swFile.Write(strRow & vbCrLf)

                    For r = 0 To ResultTable.Rows.Count - 1
                        strRow = ""
                        For c = 0 To ResultTable.Columns.Count - 1
                            If _isFullTable Then
                                If c = 0 Or c = 1 Or c = 4 Or c = 5 Then
                                    strRow &= "'" & ResultTable.Rows(r)(c) & ","
                                Else
                                    strRow &= ResultTable.Rows(r)(c) & ","
                                End If
                            Else
                                strRow &= ResultTable.Rows(r)(c) & ","
                            End If
                        Next c
                        swFile.Write(strRow & vbCrLf)
                    Next r

                Catch ex As Exception
                    log.WriteLogError("SaveResultCsv():" & strFileName, ex.Message)
                End Try
                swFile.Close()
            End If
        End Sub


        '=====================================================================
        '函 数 名: RepeatDetection
        '参    数: 
        '返 回 值:
        '功能描述: 重复检测
        '=====================================================================
        Private Sub RepeatDetection()
            If Repeat Then
                If RepeatNum <= 0 Then Repeat = False
                If _lngPress = 1 And _startMode <> "" Then
                    _lngAutoStartTime += _timer.Interval.Milliseconds
                    Dim interval As Double = RepeatInterval - (_lngAutoStartTime / 1000)
                    LinkInfoList(0).Interval = "剩余 " & IIf(interval <= 0, "0.0", interval.ToString("0.0")) & " S"
                Else
                    _lngAutoStartTime = 0
                End If
            Else
                _lngAutoStartTime = 0
            End If


            If Repeat Then
                If _isStart = False Then
                    If _lngPress = 1 And RepeatNum > 0 And _lngAutoStartTime / 1000 > RepeatInterval Then
                        If _startMode = "B" Then
                            Repeat = False
                            Return
                        End If
                        Start()
                        RepeatNum -= 1
                    End If
                End If
            End If

        End Sub

        '=====================================================================
        '函 数 名: ScanRun
        '参    数: 
        '返 回 值:
        '功能描述: 扫码枪运行
        '=====================================================================
        Private Sub ScanRun()
            If g_udtOtherSet.blnScanGuns Then
                If g_serialPort.IsOpen Then
                    If g_serialPort.PortName <> "COM" & (1 + g_udtOtherSet.uintPortName) Then
                        g_serialPort.Close()
                    End If

                    If g_serialPort.BaudRate <> g_strBaudRate(g_udtOtherSet.uintBaudRate) Then
                        g_serialPort.Close()
                    End If
                End If
                If g_serialPort.IsOpen = False Then
                    Try
                        RemoveHandler g_serialPort.DataReceived, AddressOf OnDataReceived
                        g_serialPort.PortName = "COM" & (1 + g_udtOtherSet.uintPortName)
                        g_serialPort.Handshake = Handshake.None
                        g_serialPort.BaudRate = g_strBaudRate(g_udtOtherSet.uintBaudRate)
                        g_serialPort.DataBits = 8
                        g_serialPort.Parity = Parity.None
                        g_serialPort.StopBits = StopBits.One

                        AddHandler g_serialPort.DataReceived, AddressOf OnDataReceived

                        g_serialPort.Open()
                    Catch ex As Exception
                        RemoveHandler g_serialPort.DataReceived, AddressOf OnDataReceived
                        g_udtOtherSet.blnScanGuns = False
                        User_WritePublicValue("扫描枪有效", False, ex.Source)
                        log.WriteLogError("扫码枪启动", ex.Message)
                    End Try
                End If
            Else
                If g_serialPort.IsOpen Then
                    RemoveHandler g_serialPort.DataReceived, AddressOf OnDataReceived
                    g_serialPort.Close()
                End If
            End If
        End Sub

        '=====================================================================
        '函 数 名: OnDataReceived
        '参    数: sender 事件触发对象, e 参数
        '返 回 值:
        '功能描述: 串口接收到数据事件
        '=====================================================================
        Private Sub OnDataReceived(sender As Object, e As SerialDataReceivedEventArgs)
            Dim serialPort = TryCast(sender, SerialPort)
            If IsNothing(serialPort) Then
                Exit Sub
            End If

            Dim tail = g_udtOtherSet.uintEndChar
            Dim isEnd = False
            Try
                Dim str1 As String
                Dim bytesToRead As Integer = serialPort.BytesToRead
                Dim buffer(bytesToRead - 1) As Byte
                serialPort.Read(buffer, 0, bytesToRead)      '实时读取串口信息
                str1 = _productCodeBuffer & Encoding.ASCII.GetString(buffer)
                If str1.Count > 2 Then
                    If tail = 0 Then 'cr
                        If Mid(str1, str1.Count, 1) = vbCr Then
                            str1 = Mid(str1, 1, str1.Count - 1)
                            isEnd = True
                        End If
                    ElseIf tail = 1 Then 'lf
                        If Mid(str1, str1.Count, 1) = vbLf Then
                            str1 = Mid(str1, 1, str1.Count - 1)
                            isEnd = True
                        End If

                    Else 'cr+lf
                        If Mid(str1, str1.Count - 1, 2) = vbCrLf Then
                            str1 = Mid(str1, 1, str1.Count - 2)
                            isEnd = True
                        End If
                    End If
                End If
                Debug.Print("OnDataReceived " & str1)
                DispatcherHelper.CheckBeginInvokeOnUI(Sub()
                                                          ProductCode = str1
                                                          _productCodeBuffer = str1
                                                          If isEnd And g_udtOtherSet.blnAutoStart Then
                                                              Start()
                                                          End If
                                                      End Sub)
            Catch ex As Exception
                If serialPort.IsOpen Then
                    RemoveHandler serialPort.DataReceived, AddressOf OnDataReceived
                    serialPort.DiscardInBuffer()
                    serialPort.Close()
                End If
                g_udtOtherSet.blnScanGuns = False
                User_WritePublicValue("扫描枪有效", False, ex.Source)
                log.WriteLogError("扫码枪数据接收", ex.Message)
            End Try
        End Sub

        'Private Sub WriteProduct()
        '    udtFl800.IsWritten = False
        '    If g_udt800.IsMs Then
        '        udtFl800.Write(Chr(SerialPortServer.ENQ) & "2", SystemData.WriteGroupCmd)
        '    Else
        '        If Version = Version_800_113 Then
        '            udtFl800.Write(Chr(SerialPortServer.ENQ) & "2", SystemData.WriteGroupCmd)
        '        Else
        '            udtFl800.Write(Chr(SerialPortServer.ENQ) & "9", SystemData.WriteGroupCmd)
        '        End If

        '    End If
        'End Sub

        Private Function WriteProduct() As Boolean
            IsReadOther = True
            If g_udt800.IsMs Then
                Return g_udtFL800Sync.WriteGroupSync(Chr(SerialPortServer.ENQ) & "2")
            Else
                If Version = Version_800_113 Then
                    Return g_udtFL800Sync.WriteGroupSync(Chr(SerialPortServer.ENQ) & "2")
                Else
                    Return g_udtFL800Sync.WriteGroupSync(Chr(SerialPortServer.ENQ) & "9")
                End If
            End If
            IsReadOther = False
        End Function


        '======================================================================================
        '函 数 名: ChartInit
        '参    数: 
        '返 回 值: 
        '功能描述: 设置坐标轴极值，清空点数据
        '======================================================================================
        Private Sub ChartInit()
            Debug.Print("ChartInit")
            '直压 坐标轴极限
            If g_udtOtherSet.blnAutoAxisY Then
                MinY1 = -_sngAxisInterval
                MaxY1 = _sngAxisInterval
            Else
                MinY1 = g_udtOtherSet.sngMinAxisY
                MaxY1 = g_udtOtherSet.sngMaxAxisY
            End If

            '差压 坐标轴极限
            If g_udtOtherSet.blnAutoAxisY2 Then
                MinY2 = -_sngAxisInterval
                MaxY2 = _sngAxisInterval
            Else
                MinY2 = g_udtOtherSet.sngMinAxisY2
                MaxY2 = g_udtOtherSet.sngMaxAxisY2
            End If

            GpPoints.Clear()
            DpPoints.Clear()

            _waveX.Clear()
            _waveY0.Clear()
            _waveY1.Clear()
            _lngTimeTick = My.Computer.Clock.TickCount
        End Sub

        '======================================================================================
        '函 数 名: ChartAddPoint
        '参    数: 
        '返 回 值: 
        '功能描述: 曲线中添加一个直、差压数据点
        '======================================================================================
        Private Sub ChartAddPoint()
            Dim sngTime As Single = CSng(My.Computer.Clock.TickCount - _lngTimeTick) / 1000  'sec

            Dim strTime = Format(sngTime, "0.00")

            _waveX.Add(strTime)

            Dim sngTmp As Single

            If _lngPress < 5 And _lngPress > 1 Then
                If String.IsNullOrEmpty(Info.Gp2) Then
                    Exit Sub
                End If
                Dim sigGP As Single = Single.Parse(Info.Gp2)
                If g_udtOtherSet.blnAutoAxisY Then
                    sngTmp = MaxY1
                    If sigGP > sngTmp Then
                        sngTmp = CLng((sigGP / _sngAxisInterval) + 1) * _sngAxisInterval
                    End If
                    If sngTmp < _sngAxisInterval Then sngTmp = _sngAxisInterval
                    MaxY1 = sngTmp


                    sngTmp = MinY1
                    If sigGP < sngTmp Then
                        sngTmp = CLng((sigGP / _sngAxisInterval) - 1) * _sngAxisInterval
                    End If
                    If sngTmp > -_sngAxisInterval Then
                        sngTmp = -_sngAxisInterval
                    End If
                    MinY1 = sngTmp
                End If
                _waveY0.Add(sigGP)
                GpPoints.Add(New DataPoint(sngTime, sigGP))
            Else
                _waveY0.Add("")
            End If

            If _lngPress = 6 Or _lngPress = 7 Or _lngPress = 10 Or _lngPress = 11 Then
                If String.IsNullOrEmpty(Info.Dp) Then
                    Exit Sub
                End If

                Dim sigDP As Single = Single.Parse(Info.Dp)
                If g_udtOtherSet.blnAutoAxisY2 Then
                    '自动调整Y2轴
                    sngTmp = MaxY2
                    If sigDP > sngTmp Then
                        sngTmp = CLng((sigDP / _sngAxisInterval) + 1) * _sngAxisInterval
                    End If
                    If sngTmp < _sngAxisInterval Then sngTmp = _sngAxisInterval
                    MaxY2 = sngTmp

                    sngTmp = MinY2
                    If sigDP < sngTmp Then
                        sngTmp = CLng((sigDP / _sngAxisInterval) - 1) * _sngAxisInterval
                    End If
                    If sngTmp > -_sngAxisInterval Then
                        sngTmp = -_sngAxisInterval
                    End If
                    MinY2 = sngTmp
                End If
                _waveY1.Add(sigDP)
                DpPoints.Add(New DataPoint(sngTime, sigDP))
            Else
                _waveY1.Add("")
            End If
        End Sub


        '=====================================================================
        '函 数 名: Table_AddNewLine
        '参    数: 
        '返 回 值:
        '功能描述: 记录表格增加一行
        '=====================================================================
        Private Sub Table_AddNewLine()
            _curRow = ResultTable.NewRow()

            g_udtReport.RecordId = SystemData.idWorker.nextId()
            _curRow(0) = g_udtReport.ReportId
            _curRow(1) = g_udt800.Id
            _curRow(2) = g_udt800.Name
            _curRow(3) = g_udt800.Model
            _curRow(4) = IIf(ProductCode <> "", ProductCode, "空")
            _curRow(5) = g_udtReport.RecordId


            If g_udt800.IsMs Then

                _curRow(9) = g_udt800.LeakDigit
                _curRow(10) = g_udt800.LeakUnit
                _curRow(11) = g_udt800.PressureUnit
                _curRow(13) = g_udt800.GroupId

                For i = 14 To 19
                    _curRow(i) = g_udt800.Times(i - 14)
                Next

                _curRow(20) = g_udt800.TimerDigit

                For i = 21 To 24
                    _curRow(i) = g_udt800.Limits(i - 21)
                Next

                For i = 25 To 27
                    _curRow(i) = g_udt800.Limits(i - 17)
                Next

                _curRow(28) = g_udt800.MasterMode

                _curRow(29) = g_udt800.UsbMode
                _curRow(30) = g_udt800.RS232Mode
                _curRow(31) = g_udt800.Cylinder

                _curRow(32) = g_udt800.SV5Mode
                _curRow(33) = g_udt800.Sv6Mode
                _curRow(34) = g_udt800.SV7Mode
                _curRow(35) = g_udt800.SV8Mode


            Else
                _curRow(8) = g_udt800.LeakDigit
                _curRow(9) = g_udt800.LeakUnit
                _curRow(10) = g_udt800.PressureUnit
                _curRow(12) = g_udt800.GroupId

                For i = 13 To 18
                    _curRow(i) = g_udt800.Times(i - 13)
                Next

                _curRow(19) = g_udt800.Times(8)

                For i = 20 To 21
                    _curRow(i) = g_udt800.Times(i - 20)
                Next

                _curRow(22) = g_udt800.TimerDigit

                For i = 23 To 33
                    _curRow(i) = g_udt800.Limits(i - 23)
                Next

                _curRow(34) = g_udt800.WValoume
                _curRow(35) = g_udt800.MValoume
                _curRow(36) = g_udt800.MasterMode

                _curRow(37) = g_udt800.UsbMode
                _curRow(38) = g_udt800.RS232Mode
                _curRow(39) = g_udt800.Cylinder

                _curRow(40) = g_udt800.SV5Mode
                _curRow(41) = g_udt800.Sv6Mode
                _curRow(42) = g_udt800.SV7Mode
                _curRow(43) = g_udt800.SV8Mode

                _curRow(44) = g_udt800.MiddleJudgment
                _curRow(45) = g_udt800.LeadPDAC
                _curRow(46) = g_udt800.TestPDAC

            End If

            ResultTable.Rows.Add(_curRow)
        End Sub


        '=====================================================================
        '函 数 名: Table_DelBlankLine
        '参    数: 
        '返 回 值:
        '功能描述: 记录表格删除最后一行（没有填完整的记录时）
        '=====================================================================
        Private Sub Table_DelBlankLine()
            If ResultTable.Rows.Count > 0 Then
                Dim index1 As Integer
                index1 = ResultTable.Rows.Count - 1

                Dim i As UInt16

                Dim blnNeedDel As Boolean = False

                If g_udt800.IsMs Then
                    For i = 0 To g_strResult_800MS.Count - 1
                        If IsDBNull(ResultTable.Rows.Item(index1).Item(i)) Then
                            blnNeedDel = True
                        End If
                    Next
                Else
                    For i = 0 To g_strResult_800.Count - 1
                        If IsDBNull(ResultTable.Rows.Item(index1).Item(i)) Then
                            blnNeedDel = True
                        End If
                    Next
                End If

                If blnNeedDel Then
                    ResultTable.Rows.RemoveAt(index1)
                End If
            End If
        End Sub

        '=====================================================================
        '函 数 名: InitColorStatus
        '参    数: 
        '返 回 值:
        '功能描述: 初始化状态和环节默认颜色
        '=====================================================================
        Private Sub InitColorStatus()

            StateBackColorList = New ObservableCollection(Of Brush) From {
                _unActiveColor, _unActiveColor, _unActiveColor
                }
            StateFontColorList = New ObservableCollection(Of Brush) From {
                _blackColor, _blackColor, _blackColor
                }

            ResultBackColorList = New ObservableCollection(Of Brush) From {
                _normalColor, _normalColor
                }


            LinkInfoList = New ObservableCollection(Of LinkModel) From {
                New LinkModel With {
                    .Title = "准备环节",
                    .TitleColor = _blackColor,
                    .BackColor = _unActiveColor,
                    .LinkTitleColor = _unActiveColor
                    },
                New LinkModel With {
                    .Title = "延时环节",
                    .TitleColor = _blackColor,
                    .BackColor = _unActiveColor,
                    .LinkTitleColor = _unActiveColor
                    },
                New LinkModel With {
                    .Title = "充气环节",
                    .TitleColor = _blackColor,
                    .BackColor = _unActiveColor,
                    .LinkTitleColor = _unActiveColor
                    },
                New LinkModel With {
                    .Title = "平衡环节",
                    .TitleColor = _blackColor,
                    .BackColor = _unActiveColor,
                    .LinkTitleColor = _unActiveColor
                    },
                New LinkModel With {
                    .Title = "检测环节",
                    .TitleColor = _blackColor,
                    .BackColor = _unActiveColor,
                    .LinkTitleColor = _unActiveColor
                    },
                New LinkModel With {
                    .Title = "排气环节",
                    .TitleColor = _blackColor,
                    .BackColor = _unActiveColor,
                    .LinkTitleColor = _unActiveColor
                    }
                }
        End Sub

        Private Sub FlashProcess(ByVal ucPress As UShort)
            If ucPress = 0 Or ucPress = 1 Then
                _nsMain.ChangeReady()
                _readyCounter += 1
                If g_udtOtherSet.blnEnableReadPresssure AndAlso _isM4 AndAlso _readyCounter = 5 Then
                    If Not IsReadOther Then
                        Dim res As Boolean = SystemData.g_udtFL800Sync.ReadPressureSync(Chr(SerialPortServer.ENQ) & "5" & Chr(SerialPortServer.ACK))
                        Debug.Print("读取压力值：" & res)
                    End If
                    _readyCounter = 0
                End If
            ElseIf ucPress = 2 Then
                _nsMain.Change(0)
            ElseIf ucPress = 3 Then
                _readyCounter = 0
                _nsMain.Change(1)
            Else
                If SystemData.Machine = Model_800 Then
                    If ucPress = 4 Or ucPress = 9 Then
                        _nsMain.Change(1)
                    ElseIf ucPress = 5 Or ucPress = 6 Then
                        _nsMain.Change(2)
                    ElseIf ucPress = 7 Or ucPress = 10 Or ucPress = 11 Or ucPress = 12 Then
                        _nsMain.Change(3)
                    Else
                        _nsMain.Change(4)
                    End If

                ElseIf SystemData.Machine = Model_800MS Then
                    If ucPress = 4 Then
                        _nsMain.Change(2)
                    ElseIf ucPress = 5 Or ucPress = 6 Or ucPress = 9 Or ucPress = 10 Then
                        _nsMain.Change(3)
                    Else
                        _nsMain.Change(4)
                    End If
                End If
            End If

            For i = -1 To LinkInfoList.Count - 2
                If _nsMain.GetStates() <> i Then
                    LinkInfoList(i + 1).TitleColor = _blackColor
                    LinkInfoList(i + 1).BackColor = _unActiveColor
                    LinkInfoList(i + 1).LinkTitleColor = _unActiveColor
                Else
                    LinkInfoList(i + 1).TitleColor = _whiteColor
                    LinkInfoList(i + 1).BackColor = _activeColor

                    If SystemData.Machine = Model_800 Then
                        LinkInfoList(i + 1).LinkTitle = g_strPress_800(ucPress)

                    ElseIf SystemData.Machine = Model_800MS Then
                        LinkInfoList(i + 1).LinkTitle = g_strPress_800MS(ucPress)
                    End If
                    Dim notRepeat = (i = -1)
                    Dim noTimeLimit800 = (SystemData.Machine = Model_800 AndAlso (ucPress = 9 Or ucPress = 11 Or ucPress = 12))
                    Dim noTimeLimit800MS = (SystemData.Machine = Model_800MS AndAlso (ucPress = 8 Or ucPress = 10))


                    ' TODO 确认是否显示剩余时间

                    If g_udtReport.ReportId IsNot Nothing Then
                        If notRepeat Or noTimeLimit800 Or noTimeLimit800MS Then
                            LinkInfoList(i + 1).Interval = ""
                        Else
                            Dim lastTime As Double = Double.Parse(g_udt800.Times(ucPress - 2)) - ((My.Computer.Clock.TickCount - _linkTickStart) / 1000)
                            If (SystemData.Machine = Model_800 AndAlso ucPress = 10) Or (SystemData.Machine = Model_800MS AndAlso ucPress = 9) Then
                                lastTime = Double.Parse(g_udt800.Times(ucPress - 3)) - ((My.Computer.Clock.TickCount - _linkTickStart) / 1000)
                            End If
                            LinkInfoList(i + 1).Interval = "剩余 " & IIf(lastTime < 0, "0.0", lastTime.ToString("0.0")) & " S"
                        End If
                    End If
                    LinkInfoList(i + 1).LinkTitleColor = _whiteColor
                End If
            Next

        End Sub

        Public Property MachineSelectCmd As RelayCommand
            Get
                Return _machineSelectCmd
            End Get
            Set(value As RelayCommand)
                _machineSelectCmd = value
            End Set
        End Property

        Public Property OpearteCmd As RelayCommand
            Get
                Return _opearteCmd
            End Get
            Set(value As RelayCommand)
                _opearteCmd = value
            End Set
        End Property

        Public Property ResetCmd As RelayCommand
            Get
                Return _resetCmd
            End Get
            Set(value As RelayCommand)
                _resetCmd = value
            End Set
        End Property

        Public Property StateBackColorList As ObservableCollection(Of Brush)
        Public Property StateFontColorList As ObservableCollection(Of Brush)
        Public Property ResultBackColorList As ObservableCollection(Of Brush)
        Public Property LinkInfoList As ObservableCollection(Of LinkModel)

        Public Property Info As MiddleInfoModel
            Get
                Return _info
            End Get
            Set(value As MiddleInfoModel)
                _info = value
                RaisePropertyChanged()
            End Set
        End Property

        Public Property OperationText As String
            Get
                Return _operationText
            End Get
            Set(value As String)
                _operationText = value
                RaisePropertyChanged()
            End Set
        End Property

        Public Property SaveWaveCmd As RelayCommand
            Get
                Return _saveWaveCmd
            End Get
            Set(value As RelayCommand)
                _saveWaveCmd = value
            End Set
        End Property

        Public Property NgResult As String
            Get
                Return _ngResult
            End Get
            Set(value As String)
                _ngResult = value
                RaisePropertyChanged()
            End Set
        End Property

        Public Property ResultTable As DataTable
            Get
                Return _resultTable
            End Get
            Set(value As DataTable)
                _resultTable = value
                RaisePropertyChanged()
            End Set
        End Property

        Public Property StartCmd As RelayCommand
            Get
                Return _startCommand
            End Get
            Set(value As RelayCommand)
                _startCommand = value
            End Set
        End Property

        Public Property StopCmd As RelayCommand
            Get
                Return _stopCommand
            End Get
            Set(value As RelayCommand)
                _stopCommand = value
            End Set
        End Property

        Public Property StartModeCmd As RelayCommand(Of String)
            Get
                Return _startModeCommand
            End Get
            Set(value As RelayCommand(Of String))
                _startModeCommand = value
            End Set
        End Property

        Public Property MinY1 As Double
            Get
                Return _minY1
            End Get
            Set(value As Double)
                _minY1 = value
                RaisePropertyChanged()
            End Set
        End Property

        Public Property MaxY1 As Double
            Get
                Return _maxY1
            End Get
            Set(value As Double)
                _maxY1 = value
                RaisePropertyChanged()
            End Set
        End Property

        Public Property MinY2 As Double
            Get
                Return _minY2
            End Get
            Set(value As Double)
                _minY2 = value
                RaisePropertyChanged()
            End Set
        End Property

        Public Property MaxY2 As Double
            Get
                Return _maxY2
            End Get
            Set(value As Double)
                _maxY2 = value
                RaisePropertyChanged()
            End Set
        End Property

        Public Property YLabel As String
            Get
                Return _yLabel
            End Get
            Set(value As String)
                _yLabel = value
                RaisePropertyChanged()
            End Set
        End Property

        Public Property GpPoints As ObservableCollection(Of DataPoint)
            Get
                Return _gpPoints
            End Get
            Set(value As ObservableCollection(Of DataPoint))
                _gpPoints = value
            End Set
        End Property

        Public Property DpPoints As ObservableCollection(Of DataPoint)
            Get
                Return _dpPoints
            End Get
            Set(value As ObservableCollection(Of DataPoint))
                _dpPoints = value
            End Set
        End Property

        Public Property InfoHeigh As GridLength
            Get
                Return _infoHeigh
            End Get
            Set(value As GridLength)
                _infoHeigh = value
                RaisePropertyChanged()
            End Set
        End Property

        Public Property ProductSelectCmd As RelayCommand
            Get
                Return _productSelectCmd
            End Get
            Set(value As RelayCommand)
                _productSelectCmd = value
            End Set
        End Property

        Public Property EnableStart As Boolean
            Get
                Return _enableStart
            End Get
            Set(value As Boolean)
                _enableStart = value
                RaisePropertyChanged()
            End Set
        End Property

        Public Property RepeatInterval As UShort
            Get
                Return _repeatInterval
            End Get
            Set(value As UShort)
                _repeatInterval = value
            End Set
        End Property

        Public Property ProductName As String
            Get
                Return _productName
            End Get
            Set(value As String)
                _productName = value
                RaisePropertyChanged()
            End Set
        End Property

        Public Property ProductCode As String
            Get
                Return _productCode
            End Get
            Set(value As String)
                _productCode = value
                RaisePropertyChanged()
            End Set
        End Property

        Public Property ProductCodeBuffer As String
            Get
                Return _productCodeBuffer
            End Get
            Set(value As String)
                _productCodeBuffer = value
            End Set
        End Property

        Public Property Repeat As Boolean
            Get
                Return _repeat
            End Get
            Set(value As Boolean)
                _repeat = value
                RaisePropertyChanged()
            End Set
        End Property

        Public Property RepeatNum As UShort
            Get
                Return _repeatNum
            End Get
            Set(value As UShort)
                _repeatNum = value
                RaisePropertyChanged()
            End Set
        End Property

        Public Property Gp1 As String
            Get
                Return _gp1
            End Get
            Set(value As String)
                _gp1 = value
                RaisePropertyChanged()
            End Set
        End Property

        Public Property Gp2 As String
            Get
                Return _gp2
            End Get
            Set(value As String)
                _gp2 = value
                RaisePropertyChanged()
            End Set
        End Property

        Public Property Dp As String
            Get
                Return _dp
            End Get
            Set(value As String)
                _dp = value
                RaisePropertyChanged()
            End Set
        End Property

        Public Property Temp As String
            Get
                Return _temp
            End Get
            Set(value As String)
                _temp = value
                RaisePropertyChanged()
            End Set
        End Property

        Public Property EnableButton As Boolean
            Get
                Return _enableButton
            End Get
            Set(value As Boolean)
                _enableButton = value
                RaisePropertyChanged()
            End Set
        End Property

        Public Property GPTracker As String
            Get
                Return _gPTracker
            End Get
            Set(value As String)
                _gPTracker = value
            End Set
        End Property

        Public Property DPTracker As String
            Get
                Return _dPTracker
            End Get
            Set(value As String)
                _dPTracker = value
            End Set
        End Property

        Public Property ExportCmd As RelayCommand
            Get
                Return _exportCmd
            End Get
            Set(value As RelayCommand)
                _exportCmd = value
            End Set
        End Property

        Public Property ReadHistoryCmd As RelayCommand
            Get
                Return _readHistoryCmd
            End Get
            Set(value As RelayCommand)
                _readHistoryCmd = value
            End Set
        End Property

        Public Property ClearCmd As RelayCommand
            Get
                Return _clearCmd
            End Get
            Set(value As RelayCommand)
                _clearCmd = value
            End Set
        End Property

        Public Property IsReadOther As Boolean
            Get
                Return Volatile.Read(_isReadOther)

            End Get
            Set(value As Boolean)
                Volatile.Write(_isReadOther, value)
            End Set
        End Property
    End Class
End Namespace
